#include <stdlib.h>
#include <cstdint>

class WriteBuf {
  uint8_t* buf_;
  const size_t bufsize_;
  size_t offset_ = 0;

public:
  WriteBuf(uint8_t* buf, size_t bufsize) : buf_(buf), bufsize_(bufsize) {}

  // Write a uint8_t to starting address &buf[pos].
  size_t write_uint8_at(size_t pos, uint8_t x);

  // Write a uint16_t to starting address &buf_[pos] (in big endian
  // order).
  size_t write_uint16_at(size_t pos, uint16_t x);

  // Write a uint32_t to starting address &buf_[pos] (in big endian
  // order).
  size_t write_uint32_at(size_t pos, uint32_t x);

  // Write a block of bytes to starting address &buf_[pos].
  size_t write_many_at(size_t pos, uint8_t x, size_t n);

  // Write a string to starting address &buf_[pos].
  size_t write_bytes_at(size_t pos, const uint8_t* bytes, size_t n);

  // Write a uint8_t to starting address &buf[offset_].
  void write_uint8(uint8_t x);

  // Write a uint16_t to starting address &buf_[offset_] (in big endian
  // order).
  void write_uint16(uint16_t x);

  // Write a uint32_t to starting address &buf_[offset_] (in big endian
  // order).
  void write_uint32(uint32_t x);

  // Write a block of bytes to starting address &buf_[offset_].
  void write_many(uint8_t x, size_t n);

  // Write n bytes to starting address &buf_[offset_].
  void write_bytes(const uint8_t* bytes, size_t n);

  // Write a string to starting address &buf_[offset_].
  void write_string(const char* str);

  size_t offset() const;

  // Inserts an n-byte gap, so that the bytes can be written later. This is
  // usually used for size or offset fields that need to be calculated
  // later.
  size_t insert_gap(size_t n);

  void write_to_fd(int fd);
};
